<?php
namespace app\v2\controller;
use think\Controller;
use think\Request;
use think\cache\driver\Redis;

class Base extends Controller
{
    protected $param;
    protected $token;

    public function __construct()
    {
        parent::__construct();
        header('Access-Control-Allow-Origin:*');
        header("Content-type:text/html;charset=utf-8");

        $request = Request::instance();

        # 规定 接口参数必须用post获取
        $this->param = $request->post(); 
        $this->token = $this->param['token'];
        // $isLogin = $this->isLogin();
        if($isLogin['status']==1){
            //已经登录
            define('IS_LOGIN', 1);  
            define('APP_UID', $isLogin['uid']); //uid
        }else{
            //未登录
            define('IS_LOGIN', 0);
            define('APP_UID', null);
        }

        # 防止重放攻击
        // $this->preventReplay($request); 

        # 限制测试服接口仅供内部使用
        // $this->checkAllowTestPhone($request);

    }

    protected  function  isLogin()
    {
        if(!$this->token){
            return array('status'=>0,"info"=>"没有获取到token") ;
        }
        $tokenModel =  model('v2/Token');
        $uid = $tokenModel->apiDecode($this->token);
        if (!$uid) {
            return  array("status"=>0,"info"=>$tokenModel->getError());
        } 
        return array("status"=>1,"uid"=>$uid);
    }

    /**
     * 防止重放攻击 
     * 注意：需要前端配合。接口多传参数timestamp和sign和nonce。 
     *     timestamp 为当前时间戳，
     *     sign 为 MD5(传输的的参数除开sign本身并按照字母表排序拼接的字符串)，
     *     nonce 为请求唯一标识，尽量保证不重复。可以是MD5(user-agent+timestamp)
     * @param  [type] $request 请求参数
     * @return [type]        [description]
     */
    public function preventReplay($request)
    {        
        $param = $request->post();
        $path  = $request->path();
        $needPreventRoute = [ //需要处理的接口列表
            // 'v2/sendRegVerify',
            // 'v2/register',
            'v2/login',
            'v2/sendFindVerify',
            'v2/changPassword',
            'v2/feedback',
            'v2/setUserInfo',
            'v2/myInfo',
            'v2/operatorAuth',
            'v2/Operator',
            'v2/authState',
            'v2/sixnum',
            'v2/getAppConfigs',
            'v2/loanDetails',
            'v2/apply',
            'v2/myApply',
            'v2/myApplyDetails',
            'v2/countdown',
            'v2/getCard',
            'v2/getGear',
            'v2/messpages',
            'v2/messred',
            'v2/messageinfo',
            'v2/pay',
            'v2/payAction',
            'v2/BinQuery',
            'v2/bankcardbindlist',
            'v2/bankcardbind',
            'v2/bankcardunbind',
            'v2/payRecord',
            'v2/repayment',
            'v2/contract',
            'v2/feedback',
        ]; 
        if(!in_array($path, $needPreventRoute)){
            return;
        }

        $config = config();
        header('Content-type: application/json');
        ksort($param);     //按照字母表排序
        $expire    = 60;   //缓存过期时间
        $now       = time();
        $timestamp = $param['timestamp'];
        $sign      = $param['thqz_sign'];
        $redisKey  = $config['project_name'].':request_'.$param['nonce'];
        $redis     = new Redis();
        $redis -> select($config['redis_select']); //17号库

        if(empty($param['timestamp']) || empty($param['thqz_sign']) || empty($param['nonce'])){
            die (json_encode(resultArray(['error' => '缺少基础验证参数'])));
        }
        unset($param['thqz_sign']);
        $needCheckSrting = '';
        foreach ($param as $key => $value) {
            $needCheckSrting = $needCheckSrting.$value;
        }

        //判断timestamp参数是否有效
        if($now - $timestamp > $expire){
            $now = date('Y-m-d H:i:s');
            die (json_encode(resultArray(['error' => '请求已过期，请校对时间 '.$now])));
        }
        //判断请求参数是否在“集合”已存在
        if(false !== $redis->get($redisKey)){
            die (json_encode(resultArray(['error' => '请求过于频繁，请稍候重试'])));
        }
        //验证数字签名    
        if ($sign != md5($needCheckSrting) ){
            die (json_encode(resultArray(['error' => '签名验证失败'])));
        }
        //写入redis
        $res = $redis->set($redisKey, '', $expire);

        // echo '<br>时间戳：'.time();
        // echo '<br>加密后的签名：'.md5($needCheckSrting);
        // die;
    }

    /**
     * 检查接口环境  某些非线上接口禁止调用（例如：定时发送催收短信）
     * @author   yhq <934797303@qq.com>
     * @DateTime 2018-03-19T10:55:02+0800
     * @return   [type]                            [description]
     */
    public function checkApiUrl()
    {   
        if(IS_TEST_ENV){
            die('该接口只支持正式环境');
        }
    }

    /**
     * 限制测试服接口仅供内部使用
     * @author yhq <934797303@qq.com>
     * @date   2018-04-22
     * @param  [type]     $request [description]
     * @return [type]              [description]
     */
    public function checkAllowTestPhone($request)
    {
        $param = $request->param();

        if($param['phone']){
            $phone = $param['phone'];
        }else{
            $isLogin = $this->isLogin();
            if($isLogin['status']==1){  
                $phone = model('userInfo')->getPhone($isLogin['uid']);
            }
        }

        $allowTestPhone = [];
        $string = config('ALLOW_TEST_PHONE'); 
        $arr = explode('/', $string); 

        foreach ($arr as $value) {
            if (!empty($value)) {
                $allowTestPhone[] = $value;
            }
        }

        if(IS_TEST_ENV && $phone && !in_array($phone, $allowTestPhone)){
            die (json_encode(resultArray(['error' => '测试接口，请后台添加手机号白名单'])));
        }      

    }

    /**
     * 前端日志收集
     * @author yhq <934797303@qq.com>
     * @date   2018-04-23
     * @param  Request    $request [description]
     * @return [type]              [description]
     */
    public function apiErrorLog(Request $request){
        $param  = $request->param();
        $time   = date('Y-m-d :H:i:s');
        $result = "[{$time}] 参数：".json_encode($param, JSON_UNESCAPED_UNICODE);
        file_put_contents(LOGS_DIR_NAME."apiErrorLog.log", $result."\n\n", FILE_APPEND); 
        return resultArray(['data' => '日志收集成功']);
    }

    /**
     * 版本检查
     * @author yhq <934797303@qq.com>
     * @date   2018-04-25
     * @param  Request    $request [description]
     * @return [type]              [description]
     */
    public function checkVersion(Request $request)
    {
        $res = [
            'version'     => config('APP_VERSION'),
            'version_ios' => config('APP_VERSION_IOS')
        ];
        
        if(empty($res)){
            return resultArray(['error' => '获取失败']);
        }
        return resultArray(['data' => $res]);
    }


}
